﻿//
// PicoMax
// Copyright 2012 Thomas W. Holtquist
// www.skewworks.com
//
// GPL 3.0 Licensed
//

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace PicoFontCreator
{
    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();

            lblFont.Text = lblPreview.Font.Name + " (" + lblPreview.Font.Size + ")";
            UpdatePreview();
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            if (FD1.ShowDialog() == System.Windows.Forms.DialogResult.Cancel)
                return;

            lblPreview.Font = FD1.Font;
            lblFont.Text = FD1.Font.Name + " (" + FD1.Font.Size + ")";


            UpdatePreview();

        }

        private void UpdatePreview()
        {
            int i, j;
            int x = 2;
            int y = 2;
            int w = 1;
            char c;
            string s;
            Bitmap bmp = new Bitmap(pbPreview.Width, pbPreview.Height);
            Graphics g = Graphics.FromImage(bmp);
            Font fnt = lblPreview.Font;

            // Clear Image
            pbPreview.Image = null;
            Application.DoEvents();

            // Setup Graphics
            if (chkAA.Checked)
                g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
            else
                g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;

            // Calc Fixed Width
            if (chkFixed.Checked)
            {
                for (i = 33; i < 127; i++)
                {
                    c = (char)i;
                    s = new string(new char[] { c });
                    j = (int)g.MeasureString(s, fnt).Width + (int)nudKern.Value;
                    if (j > w)
                        w = j;
                }
            }

            for (i = 33; i < 127; i++)
            {
                c = (char)i;
                s = new string(new char[] { c });

                if (!chkFixed.Checked)
                    w = (int)g.MeasureString(s, fnt).Width + (int)nudKern.Value;

                if (x + w >= bmp.Width)
                {
                    x = 2;
                    y += (int)g.MeasureString(s, fnt).Height + 2;
                }

                g.DrawString(s, fnt, Brushes.Black, x, y);
                x += w;
            }


            pbPreview.Image = bmp;
        }

        private void nudKern_ValueChanged(object sender, EventArgs e)
        {
            UpdatePreview();
        }

        private void chkAA_CheckedChanged(object sender, EventArgs e)
        {
            UpdatePreview();
        }

        private void chkFixed_CheckedChanged(object sender, EventArgs e)
        {
            UpdatePreview();
        }

        private void btnGenerate_Click(object sender, EventArgs e)
        {
            int w = 1;
            int i, j;
            int x, y;
            int bc;
            int bv;
            char c;
            string s;
            Bitmap bmp = new Bitmap(pbPreview.Width, pbPreview.Height);
            Graphics g = Graphics.FromImage(bmp);
            Font fnt = lblPreview.Font;
            Color clr;

            if (SFD1.ShowDialog() == System.Windows.Forms.DialogResult.Cancel)
                return;

            // Kill duplicates
            if (File.Exists(SFD1.FileName))
                File.Delete(SFD1.FileName);

            // Create file
            FileStream FS = new FileStream(SFD1.FileName, FileMode.CreateNew, FileAccess.Write);

            // Magic Number
            byte[] b = UTF8Encoding.UTF8.GetBytes("pFnt");
            FS.Write(b, 0, b.Length);

            // Font Type
            b = new byte[1];
            if (chkFixed.Checked)
                b[0] += 1;
            if (chkAA.Checked)
                b[0] += 2;
            FS.WriteByte(b[0]);

            // Font Height
            if (fnt.Height > 255)
            {
                MessageBox.Show("Font height is too large.\r\n255 pixel limit", "PicoFont Creator");
                FS.Close();
                return;
            }
            b[0] = (byte)fnt.Height;
            FS.WriteByte(b[0]);

            // Fixed Width
            if (chkFixed.Checked)
            {
                // Load standard characters
                for (i = 33; i < 127; i++)
                {
                    c = (char)i;
                    s = new string(new char[] { c });
                    j = (int)g.MeasureString(s, fnt).Width + (int)nudKern.Value;
                    if (j > w)
                        w = j;
                }
                b[0] = (byte)w;
                FS.WriteByte(b[0]);

                // Bytes per character
                i = 0;
                if (chkAA.Checked)
                    i = (int)Math.Ceiling((double)(w * Font.Height) / 2);
                else
                    i = (int)Math.Ceiling((double)(w * Font.Height) / 8);
                if (i > 255)
                {
                    MessageBox.Show("Font data size too large.", "PicoFont Creator");
                    FS.Close();
                    return;
                }
                b[0] = (byte)i;
                FS.WriteByte(b[0]);

                // Characters
                b = new byte[i];
                bmp = new Bitmap(w, Font.Height);
                g = Graphics.FromImage(bmp);
                for (i = 33; i < 127; i++)
                {
                    // Reset Variables
                    c = (char)i;
                    s = new string(new char[] { c });
                    j = 0;
                    bc = 0;
                    bv = 0;

                    // Draw Character
                    g.FillRectangle(Brushes.Black, 0, 0, bmp.Width, bmp.Height);
                    g.DrawString(s, fnt, Brushes.White, 0, 0);

                    // Get Data
                    if (chkAA.Checked)
                    {
                    }
                    else
                    {
                        for (y = 0; y < bmp.Height; y++)
                        {
                            for (x = 0; x < bmp.Width; x++)
                            {
                                clr = bmp.GetPixel(x, y);
                                switch (bc)
                                {
                                    case 0:
                                        if (clr.R > 0)
                                            bv = 128;
                                        bc = 1;
                                        break;
                                    case 1:
                                        if (clr.R > 0)
                                            bv += 64;
                                        bc = 2;
                                        break;
                                    case 2:
                                        if (clr.R > 0)
                                            bv += 32;
                                        bc = 3;
                                        break;
                                    case 3:
                                        if (clr.R > 0)
                                            bv += 16;
                                        bc = 4;
                                        break;
                                    case 4:
                                        if (clr.R > 0)
                                            bv += 8;
                                        bc = 5;
                                        break;
                                    case 5:
                                        if (clr.R > 0)
                                            bv += 4;
                                        bc = 6;
                                        break;
                                    case 6:
                                        if (clr.R > 0)
                                            bv += 2;
                                        bc = 7;
                                        break;
                                    case 7:
                                        if (clr.R > 0)
                                            bv += 1;
                                        b[j++] = (byte)bv;
                                        bv = 0;
                                        bc = 0;
                                        break;
                                }
                            }
                        }

                        if (bc > 0)
                            b[j++] = (byte)bv;
                        FS.Write(b, 0, b.Length);
                    }

                }

            }
            else     // Variable Width
            {
                // Characters
                for (i = 33; i < 127; i++)
                {
                    // Reset Variables
                    c = (char)i;
                    s = new string(new char[] { c });
                    j = 0;
                    bc = 0;
                    bv = 0;

                    // Prepare Bitmap
                    bmp = new Bitmap((int)g.MeasureString(s, fnt).Width, fnt.Height);
                    g = Graphics.FromImage(bmp);

                    // Draw Character
                    g.FillRectangle(Brushes.Black, 0, 0, bmp.Width, bmp.Height);
                    g.DrawString(s, fnt, Brushes.White, 0, 0);

                    // Get Data
                    if (chkAA.Checked)
                        throw new Exception("Anti-alias not yet supported");
                    else
                    {
                        // Find Start X
                        int sX = 0;
                        bool bFound;
                        for (x = 0; x < bmp.Width; x++)
                        {
                            bFound = false;
                            for (y = 0; y < bmp.Height; y++)
                            {
                                clr = bmp.GetPixel(x, y);
                                if (clr.R > 0)
                                {
                                    bFound = true;
                                    break;
                                }
                            }
                            if (bFound)
                            {
                                sX = x;
                                break;
                            }
                        }

                        // Find End X
                        int eX = sX;
                        for (x = bmp.Width - 1; x > eX; x--)
                        {
                                bFound = false;
                            for (y = 0; y < bmp.Height - 1; y++)
                            {
                                clr = bmp.GetPixel(x, y);
                                if (clr.R > 0)
                                    bFound = true;
                            }
                            if (bFound)
                            {
                                eX = x + 1;
                                break;
                            }
                        }
                        if (eX == sX)
                            eX += 1;

                        b = new byte[(int)Math.Ceiling((decimal)((eX - sX) * bmp.Height) / 8)];
                        if (b.Length > 255)
                        {
                            MessageBox.Show("Font data size too large.", "PicoFont Creator");
                            FS.Close();
                            return;
                        }
                        FS.WriteByte((byte)b.Length);

                        for (y = 0; y < bmp.Height; y++)
                        {
                            for (x = sX; x < eX; x++)
                            {
                                clr = bmp.GetPixel(x, y);
                                switch (bc)
                                {
                                    case 0:
                                        if (clr.R > 0)
                                            bv = 128;
                                        bc = 1;
                                        break;
                                    case 1:
                                        if (clr.R > 0)
                                            bv += 64;
                                        bc = 2;
                                        break;
                                    case 2:
                                        if (clr.R > 0)
                                            bv += 32;
                                        bc = 3;
                                        break;
                                    case 3:
                                        if (clr.R > 0)
                                            bv += 16;
                                        bc = 4;
                                        break;
                                    case 4:
                                        if (clr.R > 0)
                                            bv += 8;
                                        bc = 5;
                                        break;
                                    case 5:
                                        if (clr.R > 0)
                                            bv += 4;
                                        bc = 6;
                                        break;
                                    case 6:
                                        if (clr.R > 0)
                                            bv += 2;
                                        bc = 7;
                                        break;
                                    case 7:
                                        if (clr.R > 0)
                                            bv += 1;
                                        b[j++] = (byte)bv;
                                        bv = 0;
                                        bc = 0;
                                        break;
                                }
                            }
                        }

                        if (bc > 0)
                            b[j++] = (byte)bv;

                        FS.Write(b, 0, b.Length);

                    }
                }
            }

            // Close file
            FS.Close();

            // Inform user
            MessageBox.Show("PicoFont created", "PicoFont Converter", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

    }
}
